package com.intelligent.eayon.server;

import com.intelligent.eayon.coder.TransMsgDecoder;
import com.intelligent.eayon.coder.TransMsgEncoder;
import com.intelligent.eayon.config.Config;
import com.intelligent.eayon.handler.AdapterHandler;
import com.intelligent.eayon.handler.ProtocolDecoderHandler;
import com.intelligent.eayon.utils.IpUtils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;

@Component
public class Server {

    @Autowired
    private Config config;

    private static Logger logger = LoggerFactory.getLogger(Server.class);

    private static String serverIp = IpUtils.getLocalIp("eth");

    private static int serverPort = 55555;

    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel channel;

    /**
     * CKServer
     */
    public void initServer() {
            //Properties properties = new Properties();
            //properties.load(new FileReader("C:\\Users\\dmsoft\\Documents\\WeChat Files\\lauNiceyang\\Files\\NATO\\test\\src\\main\\resources\\application.properties"));
            //properties.load(Server.class.getClassLoader().getResourceAsStream("application.properties"));
            config.setServerIP(serverIp);
            config.setServerPort(String.valueOf(serverPort));
        if (!StringUtils.isEmpty(config.getServerIP())) {
            if (IpUtils.isIP(config.getServerIP())) {
                serverIp = config.getServerIP();
            } else {
                logger.error("Illegal IP in properties. use default IP:" + serverIp);
            }
        }
        if (!StringUtils.isEmpty(config.getServerPort())) {
            if (IpUtils.isPort(config.getServerPort())) {
                serverPort = Integer.parseInt(config.getServerPort());
            } else {
                logger.error("Illegal port in properties. use default IP:" + serverPort);
            }
        }
    }

    /**
     * Start the DA Server for TCP.
     */
    @PostConstruct
    public void start() {
        try {
            logger.info("Starting DA Server...");
            ServerBootstrap b = new ServerBootstrap();
            bossGroup = new NioEventLoopGroup();
            workerGroup = new NioEventLoopGroup();
            b.group(bossGroup, workerGroup);
            b.channel(NioServerSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);

            b.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    pipeline.addLast("TransMsgEncoder", new TransMsgEncoder());
                    pipeline.addLast("TransMsgDecoder", new TransMsgDecoder());

                    pipeline.addLast("ProtocolDecoderHandler", new ProtocolDecoderHandler());
                    pipeline.addLast("AdapterHandler", new AdapterHandler());

                }
            });
            //initServer();
            ChannelFuture f = b.bind(serverIp, serverPort).sync();
            logger.info("Binding ip:{}, port:{}.", serverIp, serverPort);
            channel = f.channel();
            channel.closeFuture().sync();

        } catch (Exception e) {
            logger.error("Unexpected exception from client " + e.getMessage());
        } finally {
            shutdown();
        }
    }

    private void shutdown() {
        logger.info("destroy server resources");
        if (null == channel) {
            logger.error("server channel is null");
        } else {
            channel.closeFuture().syncUninterruptibly();
        }
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
        bossGroup = null;
        workerGroup = null;
        channel = null;
    }
}
